
import java.util.*;
import java.io.Closeable;

/**
 * KaiwuDB 客户端 Java API
 * 通过 JNI 调用原生 C++ 库实现数据库操作
 * 
 * @version 1.0
 * @since 2024
 */
public class TelegrafDB implements Closeable {
    private static final String DEFAULT_CONFIG_FILE = "kwdb_jdk.ini";
    private static final String LIBRARY_NAME =  "telegraf";  // 对应 libtelegraf.so
    
    static {
        try {
            System.loadLibrary(LIBRARY_NAME);
            System.out.println("Successfully loaded native library: " + LIBRARY_NAME);
        } catch (UnsatisfiedLinkError e) {
            System.err.println("Unable to load native library " + LIBRARY_NAME + ": " + e.getMessage());
            System.err.println("Check the library!!! ");
            throw e;
        }
    }
    
    private long nativeHandle = 0;
    private boolean isClosed = false;
    
    // 连接状态常量
    public static final int CONNECTION_OK = 0;
    public static final int CONNECTION_FAILED = 1;
    public static final int CONNECTION_BAD = 2;
    
    // 返回码常量
    public static final int DBCI_OK = 0;
    public static final int DBCI_ERROR = -1;
    public static final int DBCIERR_INSERT_FAIL = -2;
    public static final int DBCIERR_CONNECT_FAIL = -3;
    
    // 插入模式常量
    public static final int MODE_AUTO_CREATE_TABLE = 0;
    public static final int MODE_MANUAL_CREATE_TABLE = 1;
    
    /**
     * 使用默认配置文件构造实例
     */
    public TelegrafDB() {
        this(DEFAULT_CONFIG_FILE);
    }
    
    /**
     * 使用指定配置文件构造实例
     * @param configFile 配置文件路径
     * @throws IllegalStateException 如果实例创建失败
     */
    public TelegrafDB(String configFile) {
        if (configFile == null || configFile.trim().isEmpty()) {
            configFile = DEFAULT_CONFIG_FILE;
        }
        
        try {
            nativeHandle = createInstance(configFile);
            if (nativeHandle == 0) {
                throw new IllegalStateException("Unable to create a native database instance!");
            }
        } catch (Exception e) {
            throw new IllegalStateException("Database instance initialization failed:" + e.getMessage(), e);
        }
    }
    
    /**
     * 检查实例是否有效
     * @throws IllegalStateException 如果实例已关闭或无效
     */
    private void checkState() {
        if (isClosed) {
            throw new IllegalStateException("TelegrafDB instance closed");
        }
        if (nativeHandle == 0) {
            throw new IllegalStateException("TelegrafDB Invalid instance");
        }
    }
    
    // ========== 配置管理 ==========
    
    /**
     * 重新加载配置
     * @param configFile 配置文件路径
     */
    public void loadConfig(String configFile) {
        checkState();
        loadConfig(nativeHandle, configFile);
    }
    
    /**
     * 打印当前配置信息
     */
    public void printConfig() {
        checkState();
        printConfig(nativeHandle);
    }
    
    // ========== 时序数据库操作 ==========
    
    /**
     * 登录时序数据库
     * @return 登录结果代码
     * @see #DBCI_OK
     * @see #DBCIERR_CONNECT_FAIL
     */
    public int login() {
        checkState();
        return login(nativeHandle);
    }
    
    /**
     * 插入时序数据
     * @param postData Telegraf Line Protocol 格式数据
     * @param mode 插入模式
     * @return 插入结果代码
     * @see #MODE_AUTO_CREATE_TABLE
     * @see #MODE_MANUAL_CREATE_TABLE
     * @see #DBCI_OK
     * @see #DBCIERR_INSERT_FAIL
     */
    public int insertData(String postData, int mode) {
        checkState();
        if (postData == null || postData.trim().isEmpty()) {
            throw new IllegalArgumentException("The inserted data cannot be empty!!!");
        }
        return insertData(nativeHandle, postData, mode);
    }
    
    /**
     * 插入时序数据（自动建表模式）
     * @param postData Telegraf Line Protocol 格式数据
     * @return 插入结果代码
     */
    public int insertData(String postData) {
        return insertData(postData, MODE_AUTO_CREATE_TABLE);
    }
    
    // ========== 关系数据库操作 ==========
    
    /**
     * 连接关系数据库
     * @param database 数据库名称，为空使用默认数据库
     * @return 连接状态
     * @see #CONNECTION_OK
     * @see #CONNECTION_FAILED
     * @see #CONNECTION_BAD
     */
    public int connectInitDB(String database) {
        checkState();
        return connectInitDB(nativeHandle, database);
    }
    
    /**
     * 连接默认数据库
     * @return 连接状态
     */
    public int connectInitDB() {
        return connectInitDB("");
    }
    
    /**
     * 断开数据库连接
     */
    public void disconnectFromDB() {
        if (!isClosed && nativeHandle != 0) {
            disconnectFromDB(nativeHandle);
        }
    }
    
    /**
     * 检查数据库连接状态
     * @return true 如果连接正常
     */
    public boolean isDBConnected() {
        if (isClosed || nativeHandle == 0) {
            return false;
        }
        return isDBConnected(nativeHandle);
    }
    
    // ========== 数据库管理 ==========
    
    /**
     * 创建数据库
     * @param dbName 数据库名称
     * @return true 如果创建成功
     */
    public boolean createDatabase(String dbName) {
        checkState();
        if (dbName == null || dbName.trim().isEmpty()) {
            throw new IllegalArgumentException("The database name cannot be empty!");
        }
        return createDatabase(nativeHandle, dbName);
    }
    
    /**
     * 选择数据库
     * @param dbName 数据库名称
     * @return true 如果选择成功
     */
    public boolean useDatabase(String dbName) {
        checkState();
        if (dbName == null || dbName.trim().isEmpty()) {
            throw new IllegalArgumentException("The database name cannot be empty!");
        }
        return useDatabase(nativeHandle, dbName);
    }
    
    // ========== 表管理 ==========
    
    /**
     * 检查表是否存在
     * @param tableName 表名称
     * @return true 如果表存在
     */
    public boolean tableExists(String tableName) {
        checkState();
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("The table name cannot be empty!");
        }
        return tableExists(nativeHandle, tableName);
    }
    
    /**
     * 创建表
     * @param tableName 表名称
     * @param columns 列定义数组
     * @param primaryKey 主键列名
     * @return true 如果创建成功
     */
    public boolean createTable(String tableName, String[] columns, String primaryKey) {
        checkState();
        validateTableOperationParams(tableName, columns);
        return createTable(nativeHandle, tableName, columns, primaryKey);
    }
    
    /**
     * 创建表（无主键）
     * @param tableName 表名称
     * @param columns 列定义数组
     * @return true 如果创建成功
     */
    public boolean createTable(String tableName, String[] columns) {
        return createTable(tableName, columns, "");
    }
    
    /**
     * 如果表不存在则创建
     * @param tableName 表名称
     * @param columns 列定义数组
     * @param primaryKey 主键列名
     * @return true 如果创建成功或表已存在
     */
    public boolean createTableIfNotExists(String tableName, String[] columns, String primaryKey) {
        checkState();
        validateTableOperationParams(tableName, columns);
        return createTableIfNotExists(nativeHandle, tableName, columns, primaryKey);
    }
    
    /**
     * 如果表不存在则创建（无主键）
     * @param tableName 表名称
     * @param columns 列定义数组
     * @return true 如果创建成功或表已存在
     */
    public boolean createTableIfNotExists(String tableName, String[] columns) {
        return createTableIfNotExists(tableName, columns, "");
    }
    
    /**
     * 删除表
     * @param tableName 表名称
     * @return true 如果删除成功
     */
    public boolean dropTable(String tableName) {
        checkState();
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("The table name cannot be empty!");
        }
        return dropTable(nativeHandle, tableName);
    }
    
    // ========== 数据操作 ==========
    
    /**
     * 插入单条数据
     * @param tableName 表名称
     * @param data 数据Map
     * @return true 如果插入成功
     */
    public boolean insertToDB(String tableName, Map<String, String> data) {
        checkState();
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("The table name cannot be empty!");
        }
        if (data == null || data.isEmpty()) {
            throw new IllegalArgumentException("The inserted data cannot be empty!");
        }
        
        String jsonData = JsonUtils.toJson(data);
        return insertToDB(nativeHandle, tableName, jsonData);
    }
    
    /**
     * 批量插入数据
     * @param tableName 表名称
     * @param dataList 数据列表
     * @return true 如果插入成功
     */
    public boolean batchInsertToDB(String tableName, List<Map<String, String>> dataList) {
        checkState();
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("The table name cannot be empty!");
        }
        if (dataList == null || dataList.isEmpty()) {
            throw new IllegalArgumentException("The batch insertion data cannot be empty!");
        }
        
        String jsonArray = JsonUtils.toJsonArray(dataList);
        return batchInsertToDB(nativeHandle, tableName, jsonArray);
    }
    
    /**
     * 执行SQL命令（无返回数据）
     * @param sql SQL语句
     * @return true 如果执行成功
     */
    public boolean executeCommand(String sql) {
        checkState();
        if (sql == null || sql.trim().isEmpty()) {
            throw new IllegalArgumentException("The SQL statement cannot be empty!");
        }
        return executeCommand(nativeHandle, sql);
    }
    
    // ========== 查询操作 ==========
    
    /**
     * 执行SQL查询
     * @param sql SQL查询语句
     * @return JSON格式的查询结果
     */
    public String executeQuery(String sql) {
        checkState();
        if (sql == null || sql.trim().isEmpty()) {
            throw new IllegalArgumentException("The SQL statement cannot be empty!");
        }
        return executeQuery(nativeHandle, sql);
    }
    
    /**
     * 查询表中的数据
     * @param tableName 表名称
     * @param columns 要查询的列数组，为空查询所有列
     * @param whereClause WHERE条件
     * @param orderBy 排序条件
     * @param limit 限制条数
     * @return JSON格式的查询结果
     */
    public String selectFromDB(String tableName, String[] columns, 
                              String whereClause, String orderBy, int limit) {
        checkState();
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("The table name cannot be empty!");
        }
        
        if (columns == null) {
            columns = new String[0];
        }
        
        return selectFromDB(nativeHandle, tableName, columns, whereClause, orderBy, limit);
    }
    
    /**
     * 查询表中所有数据
     * @param tableName 表名称
     * @return JSON格式的查询结果
     */
    public String selectAll(String tableName) {
        return selectFromDB(tableName, null, "", "", -1);
    }
    
    /**
     * 获取表中的记录数量
     * @param tableName 表名称
     * @param whereClause WHERE条件
     * @return 记录数量，错误返回-1
     */
    public int getRowCount(String tableName, String whereClause) {
        checkState();
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("The table name cannot be empty!");
        }
        return getRowCount(nativeHandle, tableName, whereClause);
    }
    
    /**
     * 获取表中的总记录数
     * @param tableName 表名称
     * @return 记录数量，错误返回-1
     */
    public int getRowCount(String tableName) {
        return getRowCount(tableName, "");
    }
    
    // ========== 工具函数 ==========
    
    /**
     * 获取最后错误信息
     * @return 错误信息字符串
     */
    public String getLastError() {
        if (isClosed || nativeHandle == 0) {
            return "instance is closed!!!";
        }
        return getLastError(nativeHandle);
    }
    
    /**
     * 设置查询超时时间
     * @param seconds 超时秒数
     */
    public void setQueryTimeout(int seconds) {
        checkState();
        if (seconds < 0) {
            throw new IllegalArgumentException("The timeout cannot be negative!!!");
        }
        setQueryTimeout(nativeHandle, seconds);
    }
    
    // ========== 资源管理 ==========
    
    /**
     * 关闭数据库连接并释放资源
     */
    @Override
    public void close() {
        if (!isClosed) {
            disconnectFromDB();
            if (nativeHandle != 0) {
                destroyInstance(nativeHandle);
                nativeHandle = 0;
            }
            isClosed = true;
        }
    }
    
    /**
     * 检查实例是否已关闭
     * @return true 如果实例已关闭
     */
    public boolean isClosed() {
        return isClosed;
    }
    
    @Override
    protected void finalize() throws Throwable {
        try {
            if (!isClosed) {
                System.err.println("Warning: The TelegrafDB instance has not been shut down properly and is being automatically cleaned up");
                close();
            }
        } finally {
            super.finalize();
        }
    }
    
    // ========== 参数验证 ==========
    
    private void validateTableOperationParams(String tableName, String[] columns) {
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("The table name cannot be empty!");
        }
        if (columns == null || columns.length == 0) {
            throw new IllegalArgumentException("Column definition cannot be empty!");
        }
        for (String column : columns) {
            if (column == null || column.trim().isEmpty()) {
                throw new IllegalArgumentException("Column names cannot be empty!");
            }
        }
    }
    
    // ========== Native方法声明 ==========
    
    private native long createInstance(String filename);
    private native void destroyInstance(long handle);
    private native void loadConfig(long handle, String filename);
    private native void printConfig(long handle);
    private native int login(long handle);
    private native int insertData(long handle, String postData, int mode);
    private native int connectInitDB(long handle, String database);
    private native void disconnectFromDB(long handle);
    private native boolean isDBConnected(long handle);
    private native boolean createDatabase(long handle, String dbName);
    private native boolean useDatabase(long handle, String dbName);
    private native boolean tableExists(long handle, String tableName);
    private native boolean createTable(long handle, String tableName, String[] columns, String primaryKey);
    private native boolean createTableIfNotExists(long handle, String tableName, String[] columns, String primaryKey);
    private native boolean dropTable(long handle, String tableName);
    private native boolean insertToDB(long handle, String tableName, String jsonData);
    private native boolean executeCommand(long handle, String sql);
    private native int getRowCount(long handle, String tableName, String whereClause);
    private native boolean batchInsertToDB(long handle, String tableName, String jsonArray);
    private native String executeQuery(long handle, String sql);
    private native String selectFromDB(long handle, String tableName, String[] columns, 
                                     String whereClause, String orderBy, int limit);
    private native String getLastError(long handle);
    private native void setQueryTimeout(long handle, int seconds);
}

/**
 * JSON工具类
 */
class JsonUtils {
    
    private JsonUtils() {
        // 工具类，防止实例化
    }
    
    /**
     * 将Map转换为JSON字符串
     */
    public static String toJson(Map<String, String> data) {
        if (data == null || data.isEmpty()) {
            return "{}";
        }
        
        StringBuilder json = new StringBuilder("{");
        int count = 0;
        for (Map.Entry<String, String> entry : data.entrySet()) {
            if (count > 0) {
                json.append(",");
            }
            json.append("\"").append(escapeJson(entry.getKey())).append("\":")
                .append("\"").append(escapeJson(entry.getValue())).append("\"");
            count++;
        }
        json.append("}");
        return json.toString();
    }
    
    /**
     * 将数据列表转换为JSON数组
     */
    public static String toJsonArray(List<Map<String, String>> dataList) {
        if (dataList == null || dataList.isEmpty()) {
            return "[]";
        }
        
        StringBuilder json = new StringBuilder("[");
        for (int i = 0; i < dataList.size(); i++) {
            if (i > 0) {
                json.append(",");
            }
            json.append(toJson(dataList.get(i)));
        }
        json.append("]");
        return json.toString();
    }
    
    /**
     * 转义JSON字符串中的特殊字符
     */
    private static String escapeJson(String str) {
        if (str == null) {
            return "";
        }
        
        return str.replace("\\", "\\\\")
                 .replace("\"", "\\\"")
                 .replace("\b", "\\b")
                 .replace("\f", "\\f")
                 .replace("\n", "\\n")
                 .replace("\r", "\\r")
                 .replace("\t", "\\t");
    }
}